package git.soulbgm.common.socket;

import git.soulbgm.common.exception.UninitializedException;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;

/**
 * 监控中心服务器
 *
 * @author SoulBGM
 * @date 2024/04/07
 */
public class MonitorCenterServer {

    private static MonitorCenterServer server;

    private static NioEventLoopGroup group;
    private static Channel channel;
    private static final int MAX_BUFFER = 1024 * 1024 * 2;

    /**
     * 监控中心服务
     *
     * @param handler  处理程序
     * @param bindPort 绑定端口
     * @throws InterruptedException 中断异常
     */
    private MonitorCenterServer(MonitorDataHandler handler, int bindPort) throws InterruptedException {
        group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.IP_MULTICAST_TTL, 16)
                .option(ChannelOption.SO_SNDBUF, MAX_BUFFER)
                .option(ChannelOption.SO_RCVBUF, MAX_BUFFER)
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(MAX_BUFFER))
                .handler(handler);

        channel = bootstrap.bind(bindPort).sync().channel();
    }

    /**
     * 获取监控中心服务
     *
     * @throws InterruptedException 中断异常
     */
    public static void initServer(MonitorDataHandler handler, int bindPort) throws InterruptedException {
        if (server == null) {
            server = new MonitorCenterServer(handler, bindPort);
        }
    }

    /**
     * 获取监控中心服务
     *
     * @return {@link MonitorCenterServer}
     */
    public static MonitorCenterServer getServer() {
        if (server == null) {
            throw new UninitializedException("未调用initServer方法进行初始化");
        }
        return server;
    }

    /**
     * 发送数据
     *
     * @param ip   ip
     * @param port 端口
     * @param data 数据
     */
    public void send(String ip, int port, byte[] data) {
        channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(data), new InetSocketAddress(ip, port)));
    }

    /**
     * 关闭通道和组
     */
    public static void close() {
        if (channel != null) {
            channel.close();
        }
        if (group != null) {
            group.shutdownGracefully();
        }
    }

    /**
     * 最后确定
     *
     * @throws Throwable 可抛出异常
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        close();
    }
}
